
/**
 * #info
 *
 *@author   wuwg
 *@createTime   2018/03/20
 *@updateTime   2018/04/12
 *@description  input-number  component 数字输入框组件
 */
/**
 * #item
 *
 * @type        aty-input-number
 * @cn          数字输入框
 * @nameprop   label
 * @menu        表单
 * @order   12
 * @stPlugin    true
 * @stContainer false
 * @mixins      [./components/components/form/form-item/form-item.js]
 */
import config from '../../../config/config.js'

import formItem from '../form-item/form-item.js'

const componentName = config.prefix + '-input-number'

const iconPrefixCls = config.prefix + '-icon'
// module
const module = {
  name: config.prefix + '-input-number',
  // 混入
  mixins: [formItem],
  components: {},
  props: {
    /**
     * #property
     *
     * @name    value
     * @cn      值
     * @group   基本属性
     * @type    number
     * @bind    must
     * @description input的值
     */
    value: {
      type: Number
    },
    /**
     * #property
     *
     * @name    step
     * @cn      每次改变的步伐
     * @group   基本属性
     * @type    number
     * @bind    must
     * @value   1
     * @description number inputs 每次改变的步伐，可以是小数
     */
    step: {
      type: Number,
      default: 1
    },
    /**
     * #property
     *
     * @name    precision
     * @cn       精确小数点位数
     * @group   基本属性
     * @type    number
     * @bind    must
     * @value   0
     * @description 该输入框精确到小数点的位数, 指定为0则表示只能输入整数
     */
    precision: {
      type: Number,
      default: 0,
      validator (value) {
        return value >= 0
      },
    },
    /**
     * #property
     *
     * @name    elementId
     * @cn      input id
     * @group   基本属性
     * @type    string
     * @description 该输入框上的id
     */
    elementId: {
      type: String
    },
    /**
     * #property
     *
     * @name    formatter
     * @cn      格式化数据
     * @group   基本属性
     * @type    function
     * @bind    must
     * @description 该输入框上的值格式化的函数或函数名
     */
    formatter: {
      type: Function
    },
    /**
     * #property
     *
     * @name    parser
     * @cn      解析函数
     * @group   数据
     * @type    function
     * @bind    must
     * @description 解析用户输入的字符, 每次输入都会调用. 参数为输入框的值
     */
    parser: {
      type: Function
    }
  },
  data () {
    return {
      // 上箭头是否禁用
      upDisabled: false,
      // 下箭头是否禁用
      downDisabled: false
    }
  },
  watch: {
    min () {
      this.changeVal(this.value)
    },
    max () {
      this.changeVal(this.value)
    }
  },
  computed: {
    inputListeners: function () {
      const _this = this
      // `Object.assign` 将所有的对象合并为一个新对象
      return Object.assign({},
        // 从父级添加所有的监听器
        this.$listeners,
        // 自定义监听器，或覆写一些监听器的行为
        {
          blur: function (event) {
            _this.$emit('blur', event)
            _this.validate()
          },
          keydown: function (event) {
            if (event.keyCode === 38) {
              event.preventDefault()
              _this.up(event)
            } else if (event.keyCode === 40) {
              event.preventDefault()
              _this.down(event)
            } else if ((_this.precision === 0 || event.target.value.includes('.')) && _this.isPointKey(event.keyCode)) {
              // 没指定小数位数 并且 输入了点
              event.preventDefault()
            } else if (_this.precision > 0) {
              const val = event.target.value
              console.log(event)
              if (val.includes('.') && val.split(".")[1].length === _this.precision && event.target.selectionStart > val.indexOf('.') && _this.isNumberKey(event.keyCode)) {
                event.preventDefault()
              }
            } else {
              _this.$emit('keydown', event)
            }
          },
          input: function (event) {
            // if (event.target.value > _this.max) {
            //   event.target.value = _this.value
            //   event.preventDefault()
            //   return
            // }
            // 这里确保组件配合 `v-model` 的工作
            _this.change(event)
          },
          change: function (event) {
            _this.change(event)
          }
        }
      )
    },
    inputAttrs: function () {
      return Object.assign({},
        // 默认属性
        {
          maxlength: 16,
          autocomplete: 'off'
        },
        this.$attrs
      )
    },
    wrapClasses () {
      return [
        `${componentName}-wrapper`,
        {
          [`${componentName}-wrapper-disabled`]: this.inputAttrs.disabled !== undefined && this.inputAttrs.disabled !== false,
        }
      ].concat(this.formItemClasses)
    },
    wrapStyles () {
      return this.formItemStyles
    },
    handlerClasses () {
      return `${componentName}-handler-wrap`
    },
    upClasses () {
      return [
        `${componentName}-handler`,
        `${componentName}-handler-up`,
        {
          [`${componentName}-handler-up-disabled`]: this.upDisabled
        }
      ]
    },
    innerUpClasses () {
      return [
        `${componentName}-handler-up-inner`,
        `${iconPrefixCls}`,
        `${iconPrefixCls}-ios-arrow-up`
      ]
    },
    downClasses () {
      return [
        `${componentName}-handler`,
        `${componentName}-handler-down`,
        {
          [`${componentName}-handler-down-disabled`]: this.downDisabled
        }
      ]
    },
    innerDownClasses () {
      return [
        `${componentName}-handler-down-inner`,
        `${iconPrefixCls}`,
        `${iconPrefixCls}-ios-arrow-down`
      ]
    },
    inputClasses () {
      return `${componentName}`
    },
    formatValue: {
      // getter
      get: function () {
        return this.getFormatValue(this.value)
      },
      // setter
      set: function (newValue) {
        this.$refs.input.value = newValue
      }
    }
  },
  methods: {
    // 重置为初始值
    reset () {
      this.$refs.input.value = this._originalValue
      this.$emit('input', this._originalValue)
      this.$emit('change')
    },
    getFormatValue (value) {
      this.changeVal(value)

      if (this.formatter && value !== null) {
        return this.formatter(value)
      }

      // 如果 step 是小数，且没有设置 precision，是有问题的
      // if (!isNaN(this.precision) && !isNaN(value)) {
      //   return Number(value).toFixed(this.precision)
      // }

      return value
    },
    preventDefault (e) {
      e.preventDefault()
    },
    up (e) {
      if (this.upDisabled) {
        return false
      }
      this.changeStep('up', e)
    },
    down (e) {
      if (this.downDisabled) {
        return false
      }
      this.changeStep('down', e)
    },
    changeStep (type, e) {
      if (this.disabled) {
        return false
      }
      let val = Number(this.value)
      val = isNaN(val) ? 0 : val
      const step = Number(this.step)
      if (type === 'up') {
        val = this.addNum(val, step)
      } else if (type === 'down') {
        val = this.addNum(val, -step)
      }
      this.setValue(val, e)
    },
    // 数字增加的方法
    addNum (num1, num2) {
      let sq1, sq2, m
      try {
        sq1 = num1.toString().split('.')[1].length
      } catch (e) {
        sq1 = 0
      }
      try {
        sq2 = num2.toString().split('.')[1].length
      } catch (e) {
        sq2 = 0
      }
      m = Math.pow(10, Math.max(sq1, sq2))
      return (Math.round(num1 * m) + Math.round(num2 * m)) / m
    },
    setValue (val, e) {
      if (this.value === val) {
        return
      }
      this.$emit('input', this.isValidValue(val) ? val : null)
      this.$emit('change', e)
    },
    isValidValue (val) {
      return !(val === null || val === undefined || val === '' || isNaN(Number(val)))
    },
    change (event) {
      let val = event.target.value.trim()
      if (val.length === 0) {
        this.setValue(null, event)
        return
      }
      if (this.parser) {
        val = this.parser(val)
      }
      // prevent fire early if decimal. If no more input the change event will fire later
      if (event.type === 'input' && val.match(/^\-?\.?$|\.$/)) {
        return
      }
      val = Number(val)
      // already fired change for input event
      if (event.type == 'change' && val === this.value) {
        return
      }
      if (isNaN(val)) {
        val = this.value !== undefined ? this.value : null
        this.$refs.input.value = val
      }
      // prevent fire early in case user is typing a bigger number. Change will handle this otherwise.
      // if (event.type == 'input' && this.min && val < this.min) {
      //   return
      // }
      // val = (!!this.max && val > this.max) ? this.max : val
      // val = (!!this.min && val < this.min) ? this.min : val
      this.setValue(val, event)
    },
    changeVal (val) {
      val = Number(val)
      if (!isNaN(val)) {
        const step = this.step

        this.upDisabled = val + step > this.max
        this.downDisabled = val - step < this.min
      } else {
        this.upDisabled = true
        this.downDisabled = true
      }
    },
    isNumberKey (key) {
      return (key >= 48 && key <= 57) || // 0-9
        (key >= 96 && key <= 105) // 小键盘0-9
    },
    isPointKey (key) {
      return key === 190 || key === 110
    }
  },
  updated () { },
  created () {
    // 保存初始值，用于reset
    this._originalValue = Artery.deepCopy(this.value)
  },
  mounted () {
    this.changeVal(this.value)
  }
}
export default module
